package cn.itsource.system.util;

import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.StrUtil;
import cn.itsource.system.annotation.PermissionAnnotation;
import cn.itsource.system.domain.Permission;
import cn.itsource.system.mapper.PermissionMapper;
import org.assertj.core.internal.Classes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义一个类 专门用来扫描 当前项目下面所有的自定义注解@PermissionAnnotation
 */
@Component
public class PermissionScanUtil {
      //扫描指定包 包都在cn.itsource路径之下
    private  String  scanPackage = "cn.itsource";
    @Autowired
    private PermissionMapper permissionMapper;
    /**
     * 1.扫描目标类有那些（扫描当前项目下面所有的@RestController注解）
     * 2.扫描这些类下面的所有的方法，并且有加@PermissionAnnotation注解的
     * 3.如果方法上面 加了此注解 那么我就要判断数据库里面是否有对应的资源
     *
     *   如果有：修改
     *   如果没有：新增
     */
    public void scan(){
        //扫描指定包 指定的注解 返回是满足条件的类 扫描拥有restController注解的控制类
        Set<Class<?>> classes1 = ClassScanner.scanAllPackageByAnnotation(scanPackage, RestController.class);
        //扫描用有@controller注解修饰的类 其实也就是控制类
        Set<Class<?>> classes2 = ClassScanner.scanAllPackageByAnnotation(scanPackage, Controller.class);
        //创建一个空集合，专门来装控制层对应的类型
        Set<Class<?>> classes = new HashSet<>();
        //添加控制器字节码集合1
        classes.addAll(classes1);
        //添加控制器字节码集合2
        classes.addAll(classes2);
         //获取所有的权限列表
         List<Permission>  permissionList=permissionMapper.seletAll();
         //把list集合转换为map
        Map<String, Permission> map = permissionList.stream().collect(Collectors.toMap(Permission::getSn, p -> p));

        //循环所有的控制器类
        for(Class<?> clz : classes){
            //获取到控制器当中  所有的公共方法
            Method[] methods = clz.getMethods();
            //循环控制类中的所有方法
            for(Method method : methods){
                //获取方法上的指定注解
                PermissionAnnotation annotation = method.getAnnotation(PermissionAnnotation.class);
                //当这个方法当中 没有@PermissionAnnotation注解 就直接跳过 继续循环
                if(annotation == null){
                    //直接结束本次循环
                    continue;
                }
                //获取权限编号
                String sn = annotation.sn();

                //获取url地址
                String url = annotation.url();

                //如果url为空 就证明 手动没有填写url 需要程序自己拼接
                if(StrUtil.isBlank(url)){
                    //获取方法上面的URL地址
                    url   =   getRequestMapppingUrl(clz,method);
                }
                //获取请求方式
                 String methodType = getMethodType(method);
                //判断map集合即permission权限列表当中 是否包含sn 如果包含就走修改
                if(map.containsKey(sn)){
                    //当权限列表中有sn 就根据sn找到对应的行 对那一行的各种属性 进行修改
                    Permission permission = map.get(sn);
                    permission.setName(annotation.name());
                    permission.setDescs(annotation.descs());
                    permission.setUrl(url);
                    permission.setMethodType(methodType);
                    permissionMapper.updateByPrimaryKey(permission);
                }else {
                    //当权限列表中没有sn 那就把所有的元素添加 相当于一种新增ef
                    Permission permission = new Permission();
                    permission.setName(annotation.name());
                    permission.setDescs(annotation.descs());
                    permission.setSn(annotation.sn());
                     permission.setUrl(url);
                     permission.setMethodType(methodType);
                    permissionMapper.insert(permission);
                }
            }
        }
    }

    private String getMethodType(Method method) {
        //获取类上的RequestMapping注解
        RequestMapping clzRequestMapping = method.getAnnotation(RequestMapping.class);
        //如果requestMapping不为空，就证明能接收一切请求
        if(clzRequestMapping!=null){
            return "";
        }
        //获取方法上的postMapping
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        //如果postMapping不为空
        if(postMapping!=null){
            return RequestMethod.POST.toString();
        }

        //获取方法上的postMapping
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
        //如果postMapping不为空
        if(deleteMapping!=null){
            return RequestMethod.DELETE.toString();
        }

        //获取方法上的postMapping
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        //如果postMapping不为空
        if(putMapping!=null){
            return RequestMethod.PUT.toString();
        }
        //获取方法上的postMapping
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        //如果postMapping不为空
        if(getMapping!=null){
            return RequestMethod.GET.toString();
        }

        //获取方法上的postMapping
        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
        //如果postMapping不为空
        if(patchMapping!=null){
            return RequestMethod.PATCH.toString();
        }
        return "";
    }

    private String getRequestMapppingUrl(Class<?> clz, Method method) {
        //获取类上的@RequestMapping注解
        RequestMapping clzRequestMapping = clz.getAnnotation(RequestMapping.class);
           //url 地址默认为字符串
        String url = "";
          // 当注解不为空 证明类上是有RequestMapping的
        if(clzRequestMapping != null){
            //获取类上的url地址
            String[] value = clzRequestMapping.value();
            //获取类上的url地址
            String url1  = value[0];
            //如果RequestMappping的那个路径 是以斜杠/开头 就不用加/
            //如果RequestMappping的那个路径不是以/开头 就需要在路径前面加/
            url =url1.startsWith("/")?url1:("/"+url1);
        }
        //获取方法上面的路径 此为获取postmapping上面的路径
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        if(postMapping!=null){
            String[] value = postMapping.value();
           if(value.length==0){
               return url;
           }else {
               String url2  = value[0];
               url =url2.startsWith("/")?(url+url2):(url+"/"+url2);
               return url;
           }
        }

        //获取方法上面的路径 此为获取deletemapping上面的路径
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
        if(deleteMapping!=null){
            String[] value = deleteMapping.value();
            if(value.length==0){
                return url;
            }else {
                String url3  = value[0];
                url =url3.startsWith("/")?(url+url3):(url+"/"+url3);
                return url;
            }
        }

        //获取方法上面的路径 此为获取Putmapping上面的路径
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        if(putMapping!=null){
            String[] value = putMapping.value();
            if(value.length==0){
                return url;
            }else {
                String url4  = value[0];
                url =url4.startsWith("/")?(url+url4):(url+"/"+url4);
                return url;
            }
        }

        //获取方法上面的路径 此为获取getmapping上面的路径
       GetMapping getMapping = method.getAnnotation(GetMapping.class);
        if(getMapping!=null){
            String[] value = getMapping.value();
            if(value.length==0){
                return url;
            }else {
                String url5  = value[0];
                url =url5.startsWith("/")?(url+url5):(url+"/"+url5);
                return url;
            }
        }

        //获取方法上面的路径 此为获取getmapping上面的路径
        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
        if(patchMapping!=null){
            String[] value = patchMapping.value();
            if(value.length==0){
                return url;
            }else {
                String url6  = value[0];
                url =url6.startsWith("/")?(url+url6):(url+"/"+url6);
                return url;
            }
        }

        //获取方法上面的路径 此为获取RequestMapping上面的路径
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        if(requestMapping!=null){
            String[] value = requestMapping.value();
            if(value.length==0){
                return url;
            }else {
                String url7  = value[0];
                url =url7.startsWith("/")?(url+url7):(url+"/"+url7);
                return url;
            }
        }
          return "";
    }
}
